home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / ftpd / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-31  |  36.9 KB  |  1,733 lines

  1. /*
  2.  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)ftpd.c    8.5 (Berkeley) 4/28/95";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * FTP server.
  46.  */
  47.  
  48. #ifdef HAVE_CONFIG_H
  49. #include <config.h>
  50. #endif
  51.  
  52. #include <sys/param.h>
  53. #include <sys/stat.h>
  54. #include <sys/ioctl.h>
  55. #include <sys/socket.h>
  56. #include <sys/wait.h>
  57.  
  58. #include <netinet/in.h>
  59. #ifdef HAVE_NETINET_IN_SYSTM_H
  60. #include <netinet/in_systm.h>
  61. #endif
  62. #ifdef HAVE_NETINET_IP_H
  63. #include <netinet/ip.h>
  64. #endif
  65.  
  66. #define    FTP_NAMES
  67. #include <arpa/ftp.h>
  68. #include <arpa/inet.h>
  69. #include <arpa/telnet.h>
  70.  
  71. #include <ctype.h>
  72. #include <dirent.h>
  73. #include <errno.h>
  74. #include <fcntl.h>
  75. #include <glob.h>
  76. #include <limits.h>
  77. #include <netdb.h>
  78. #include <pwd.h>
  79. #include <setjmp.h>
  80. #include <signal.h>
  81. #include <stdio.h>
  82. #include <stdlib.h>
  83. #include <string.h>
  84. #include <syslog.h>
  85. #include <time.h>
  86. #include <unistd.h>
  87. #include <paths.h>
  88. #include <crypt.h>
  89.  
  90. #include "extern.h"
  91.  
  92. #if __STDC__
  93. #include <stdarg.h>
  94. #else
  95. #include <varargs.h>
  96. #endif
  97.  
  98. static char version[] = "Version 6.00";
  99.  
  100. extern    off_t restart_point;
  101. extern    char cbuf[];
  102.  
  103. struct    sockaddr_in ctrl_addr;
  104. struct    sockaddr_in data_source;
  105. struct    sockaddr_in data_dest;
  106. struct    sockaddr_in his_addr;
  107. struct    sockaddr_in pasv_addr;
  108.  
  109. int    data;
  110. jmp_buf    errcatch, urgcatch;
  111. int    logged_in;
  112. struct    passwd *pw;
  113. int    debug;
  114. int    timeout = 900;    /* timeout after 15 minutes of inactivity */
  115. int    maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
  116. int    logging;
  117. int    guest;
  118. int    type;
  119. int    form;
  120. int    stru;            /* avoid C keyword */
  121. int    mode;
  122. int    usedefault = 1;        /* for data transfers */
  123. int    pdata = -1;        /* for passive mode */
  124. sig_atomic_t transflag;
  125. off_t    file_size;
  126. off_t    byte_count;
  127. #if !defined(CMASK) || CMASK == 0
  128. #undef CMASK
  129. #define CMASK 027
  130. #endif
  131. int    defumask = CMASK;        /* default umask value */
  132. char    tmpline[7];
  133. char    *hostname = 0;
  134. char    *remotehost = 0;
  135.  
  136. #define NUM_SIMUL_OFF_TO_STRS 4
  137.  
  138. /* Returns a string with the decimal representation of the off_t OFF, taking
  139.    into account that off_t might be longer than a long.  The return value is
  140.    a pointer to a static buffer, but a return value will only be reused every
  141.    NUM_SIMUL_OFF_TO_STRS calls, to allow multiple off_t's to be conveniently
  142.    printed with a single printf statement.  */
  143. static char *
  144. off_to_str (off)
  145.      off_t off;
  146. {
  147.   static char bufs[NUM_SIMUL_OFF_TO_STRS][80];
  148.   static char (*next_buf)[80] = bufs;
  149.  
  150.   if (next_buf > &bufs[NUM_SIMUL_OFF_TO_STRS])
  151.     next_buf = bufs;
  152.  
  153.   if (sizeof (off) > sizeof (long))
  154.     sprintf (*next_buf, "%qd", off);
  155.   else if (sizeof (off) == sizeof (long))
  156.     sprintf (*next_buf, "%ld", off);
  157.   else
  158.     sprintf (*next_buf, "%d", off);
  159.  
  160.   return *next_buf++;
  161. }
  162.  
  163. /*
  164.  * Timeout intervals for retrying connections
  165.  * to hosts that don't accept PORT cmds.  This
  166.  * is a kludge, but given the problems with TCP...
  167.  */
  168. #define    SWAITMAX    90    /* wait at most 90 seconds */
  169. #define    SWAITINT    5    /* interval between retries */
  170.  
  171. int    swaitmax = SWAITMAX;
  172. int    swaitint = SWAITINT;
  173.  
  174. #ifdef SETPROCTITLE
  175. char    **Argv = NULL;        /* pointer to argument vector */
  176. char    *LastArgv = NULL;    /* end of argv */
  177. char    proctitle[LINE_MAX];    /* initial part of title */
  178. #endif /* SETPROCTITLE */
  179.  
  180. #define LOGCMD(cmd, file) \
  181.     if (logging > 1) \
  182.         syslog(LOG_INFO,"%s %s%s", cmd, \
  183.         *(file) == '/' ? "" : curdir(), file);
  184. #define LOGCMD2(cmd, file1, file2) \
  185.      if (logging > 1) \
  186.         syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
  187.         *(file1) == '/' ? "" : curdir(), file1, \
  188.         *(file2) == '/' ? "" : curdir(), file2);
  189. #define LOGBYTES(cmd, file, cnt) \
  190.     if (logging > 1) { \
  191.         if (cnt == (off_t)-1) \
  192.             syslog(LOG_INFO,"%s %s%s", cmd, \
  193.             *(file) == '/' ? "" : curdir(), file); \
  194.         else \
  195.             syslog(LOG_INFO, "%s %s%s = %s bytes", \
  196.             cmd, (*(file) == '/') ? "" : curdir(), file, \
  197.                off_to_str (cnt)); \
  198.     }
  199.  
  200. static void     ack __P((char *));
  201. static void     myoob __P((int));
  202. static int     checkuser __P((char *));
  203. static FILE    *dataconn __P((char *, off_t, char *));
  204. static void     dolog __P((struct sockaddr_in *));
  205. static char    *curdir __P((void));
  206. static void     end_login __P((void));
  207. static FILE    *getdatasock __P((char *));
  208. static char    *gunique __P((char *));
  209. static void     lostconn __P((int));
  210. static int     receive_data __P((FILE *, FILE *));
  211. static void     send_data __P((FILE *, FILE *, off_t));
  212. static struct passwd *
  213.          sgetpwnam __P((char *));
  214. static char    *sgetsave __P((char *));
  215.  
  216. static char *
  217. curdir()
  218. {
  219.         static char *path = 0;
  220.     if (path)
  221.             free (path);
  222.     path = getcwd (0, 0);
  223.     if (! path)
  224.         return ("");
  225.     if (path[1] != '\0') {    /* special case for root dir. */
  226.             char *new = realloc (path, strlen (path) + 2); /* '/' + '\0' */
  227.         if (! new)
  228.                 return "";
  229.         strcat(new, "/");
  230.         path = new;
  231.     }
  232.     /* For guest account, skip / since it's chrooted */
  233.     return (guest ? path+1 : path);
  234. }
  235.  
  236. int
  237. main(argc, argv, envp)
  238.     int argc;
  239.     char *argv[];
  240.     char **envp;
  241. {
  242.         extern char *localhost ();
  243.     int addrlen, ch, on = 1, tos;
  244.     char *cp, line[LINE_MAX];
  245.     FILE *fd;
  246.  
  247.     /*
  248.      * LOG_NDELAY sets up the logging connection immediately,
  249.      * necessary for anonymous ftp's that chroot and can't do it later.
  250.      */
  251.     openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
  252.     addrlen = sizeof(his_addr);
  253.     if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  254.         syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
  255.         exit(1);
  256.     }
  257.     addrlen = sizeof(ctrl_addr);
  258.     if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
  259.         syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
  260.         exit(1);
  261.     }
  262. #if defined (IP_TOS) && defined (IPTOS_LOWDELAY) && defined (IPPROTO_IP)
  263.     tos = IPTOS_LOWDELAY;
  264.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  265.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  266. #endif
  267.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  268.     debug = 0;
  269. #ifdef SETPROCTITLE
  270.     /*
  271.      *  Save start and extent of argv for setproctitle.
  272.      */
  273.     Argv = argv;
  274.     while (*envp)
  275.         envp++;
  276.     LastArgv = envp[-1] + strlen(envp[-1]);
  277. #endif /* SETPROCTITLE */
  278.  
  279.     while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
  280.         switch (ch) {
  281.         case 'd':
  282.             debug = 1;
  283.             break;
  284.  
  285.         case 'l':
  286.             logging++;    /* > 1 == extra logging */
  287.             break;
  288.  
  289.         case 't':
  290.             timeout = atoi(optarg);
  291.             if (maxtimeout < timeout)
  292.                 maxtimeout = timeout;
  293.             break;
  294.  
  295.         case 'T':
  296.             maxtimeout = atoi(optarg);
  297.             if (timeout > maxtimeout)
  298.                 timeout = maxtimeout;
  299.             break;
  300.  
  301.         case 'u':
  302.             {
  303.             long val = 0;
  304.  
  305.             val = strtol(optarg, &optarg, 8);
  306.             if (*optarg != '\0' || val < 0)
  307.                 fprintf (stderr,
  308.                      "%s: bad value for -u", argv[0]);
  309.             else
  310.                 defumask = val;
  311.             break;
  312.             }
  313.  
  314.         case 'v':
  315.             debug = 1;
  316.             break;
  317.  
  318.         default:
  319.             fprintf (stderr,
  320.                  "%s: unknown flag -%c ignored", argv[0]);
  321.             break;
  322.         }
  323.     }
  324.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  325.     (void) signal(SIGPIPE, lostconn);
  326.     (void) signal(SIGCHLD, SIG_IGN);
  327.     if ((int)signal(SIGURG, myoob) < 0)
  328.         syslog(LOG_ERR, "signal: %m");
  329.  
  330.     /* Try to handle urgent data inline */
  331. #ifdef SO_OOBINLINE
  332.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  333.         syslog(LOG_ERR, "setsockopt: %m");
  334. #endif
  335.  
  336. #ifdef    F_SETOWN
  337.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  338.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  339. #endif
  340.     dolog(&his_addr);
  341.     /*
  342.      * Set up default state
  343.      */
  344.     data = -1;
  345.     type = TYPE_A;
  346.     form = FORM_N;
  347.     stru = STRU_F;
  348.     mode = MODE_S;
  349.     tmpline[0] = '\0';
  350.  
  351.     /* If logins are disabled, print out the message. */
  352.     if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
  353.         while (fgets(line, sizeof(line), fd) != NULL) {
  354.             if ((cp = strchr(line, '\n')) != NULL)
  355.                 *cp = '\0';
  356.             lreply(530, "%s", line);
  357.         }
  358.         (void) fflush(stdout);
  359.         (void) fclose(fd);
  360.         reply(530, "System not available.");
  361.         exit(0);
  362.     }
  363.     if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
  364.         while (fgets(line, sizeof(line), fd) != NULL) {
  365.             if ((cp = strchr(line, '\n')) != NULL)
  366.                 *cp = '\0';
  367.             lreply(220, "%s", line);
  368.         }
  369.         (void) fflush(stdout);
  370.         (void) fclose(fd);
  371.         /* reply(220,) must follow */
  372.     }
  373.             
  374.     hostname = localhost ();
  375.     if (! hostname)
  376.         perror_reply (550, "Local resource failure: malloc");
  377.  
  378.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  379.     (void) setjmp(errcatch);
  380.     for (;;)
  381.         (void) yyparse();
  382.     /* NOTREACHED */
  383. }
  384.  
  385. static void
  386. lostconn(signo)
  387.     int signo;
  388. {
  389.  
  390.     if (debug)
  391.         syslog(LOG_DEBUG, "lost connection");
  392.     dologout(-1);
  393. }
  394.  
  395. static char ttyline[20];
  396.  
  397. /*
  398.  * Helper function for sgetpwnam().
  399.  */
  400. static char *
  401. sgetsave(s)
  402.     char *s;
  403. {
  404.     char *new = malloc((unsigned) strlen(s) + 1);
  405.  
  406.     if (new == NULL) {
  407.         perror_reply(421, "Local resource failure: malloc");
  408.         dologout(1);
  409.         /* NOTREACHED */
  410.     }
  411.     (void) strcpy(new, s);
  412.     return (new);
  413. }
  414.  
  415. /*
  416.  * Save the result of a getpwnam.  Used for USER command, since
  417.  * the data returned must not be clobbered by any other command
  418.  * (e.g., globbing).
  419.  */
  420. static struct passwd *
  421. sgetpwnam(name)
  422.     char *name;
  423. {
  424.     static struct passwd save;
  425.     struct passwd *p;
  426.  
  427.     if ((p = getpwnam(name)) == NULL)
  428.         return (p);
  429.     if (save.pw_name) {
  430.         free(save.pw_name);
  431.         free(save.pw_passwd);
  432.         free(save.pw_gecos);
  433.         free(save.pw_dir);
  434.         free(save.pw_shell);
  435.     }
  436.     save = *p;
  437.     save.pw_name = sgetsave(p->pw_name);
  438.     save.pw_passwd = sgetsave(p->pw_passwd);
  439.     save.pw_gecos = sgetsave(p->pw_gecos);
  440.     save.pw_dir = sgetsave(p->pw_dir);
  441.     save.pw_shell = sgetsave(p->pw_shell);
  442.     return (&save);
  443. }
  444.  
  445. static int login_attempts;    /* number of failed login attempts */
  446. static int askpasswd;        /* had user command, ask for passwd */
  447. static char curname[10];    /* current USER name */
  448.  
  449. /*
  450.  * USER command.
  451.  * Sets global passwd pointer pw if named account exists and is acceptable;
  452.  * sets askpasswd if a PASS command is expected.  If logged in previously,
  453.  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
  454.  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
  455.  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
  456.  * requesting login privileges.  Disallow anyone who does not have a standard
  457.  * shell as returned by getusershell().  Disallow anyone mentioned in the file
  458.  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
  459.  */
  460. void
  461. user(name)
  462.     char *name;
  463. {
  464.     char *cp, *shell;
  465.  
  466.     if (logged_in) {
  467.         if (guest) {
  468.             reply(530, "Can't change user from guest login.");
  469.             return;
  470.         }
  471.         end_login();
  472.     }
  473.  
  474.     guest = 0;
  475.     if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
  476.         if (checkuser("ftp") || checkuser("anonymous"))
  477.             reply(530, "User %s access denied.", name);
  478.         else if ((pw = sgetpwnam("ftp")) != NULL) {
  479.             guest = 1;
  480.             askpasswd = 1;
  481.             reply(331,
  482.                 "Guest login ok, type your name as password.");
  483.         } else
  484.             reply(530, "User %s unknown.", name);
  485.         if (!askpasswd && logging)
  486.             syslog(LOG_NOTICE,
  487.                 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
  488.         return;
  489.     }
  490.     if (pw = sgetpwnam(name)) {
  491.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  492.             shell = _PATH_BSHELL;
  493.         while ((cp = getusershell()) != NULL)
  494.             if (strcmp(cp, shell) == 0)
  495.                 break;
  496.         endusershell();
  497.  
  498.         if (cp == NULL || checkuser(name)) {
  499.             reply(530, "User %s access denied.", name);
  500.             if (logging)
  501.                 syslog(LOG_NOTICE,
  502.                     "FTP LOGIN REFUSED FROM %s, %s",
  503.                     remotehost, name);
  504.             pw = (struct passwd *) NULL;
  505.             return;
  506.         }
  507.     }
  508.     if (logging)
  509.         strncpy(curname, name, sizeof(curname)-1);
  510.     if (pw && *pw->pw_passwd) {
  511.         reply(331, "Password required for %s.", name);
  512.         askpasswd = 1;
  513.     }
  514.     /*
  515.      * Delay before reading passwd after first failed
  516.      * attempt to slow down passwd-guessing programs.
  517.      */
  518.     if (login_attempts)
  519.         sleep((unsigned) login_attempts);
  520. }
  521.  
  522. /*
  523.  * Check if a user is in the file _PATH_FTPUSERS
  524.  */
  525. static int
  526. checkuser(name)
  527.     char *name;
  528. {
  529.     FILE *fd;
  530.     int found = 0;
  531.     char *p, line[BUFSIZ];
  532.  
  533.     if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
  534.         while (fgets(line, sizeof(line), fd) != NULL)
  535.             if ((p = strchr(line, '\n')) != NULL) {
  536.                 *p = '\0';
  537.                 if (line[0] == '#')
  538.                     continue;
  539.                 if (strcmp(line, name) == 0) {
  540.                     found = 1;
  541.                     break;
  542.                 }
  543.             }
  544.         (void) fclose(fd);
  545.     }
  546.     return (found);
  547. }
  548.  
  549. /*
  550.  * Terminate login as previous user, if any, resetting state;
  551.  * used when USER command is given or login fails.
  552.  */
  553. static void
  554. end_login()
  555. {
  556.  
  557.     (void) seteuid((uid_t)0);
  558.     if (logged_in)
  559.         logwtmp(ttyline, "", "");
  560.     pw = NULL;
  561.     logged_in = 0;
  562.     guest = 0;
  563. }
  564.  
  565. void
  566. pass(passwd)
  567.     char *passwd;
  568. {
  569.     char *salt, *xpasswd;
  570.     FILE *fd;
  571.  
  572.     if (logged_in || askpasswd == 0) {
  573.         reply(503, "Login with USER first.");
  574.         return;
  575.     }
  576.     askpasswd = 0;
  577.     if (!guest && (!pw || *pw->pw_passwd)) {
  578.         salt = pw ? pw->pw_passwd : "xx";
  579.         xpasswd = CRYPT (passwd, salt);
  580.         if (pw && *pw->pw_passwd && strcmp(xpasswd, pw->pw_passwd)) {
  581.             reply(530, "Login incorrect.");
  582.             if (logging)
  583.                 syslog(LOG_NOTICE,
  584.                     "FTP LOGIN FAILED FROM %s, %s",
  585.                     remotehost, curname);
  586.             pw = NULL;
  587.             if (login_attempts++ >= 5) {
  588.                 syslog(LOG_NOTICE,
  589.                     "repeated login failures from %s",
  590.                     remotehost);
  591.                 exit(0);
  592.             }
  593.             return;
  594.         }
  595.     }
  596.     login_attempts = 0;        /* this time successful */
  597.     if (setegid((gid_t)pw->pw_gid) < 0) {
  598.         reply(550, "Can't set gid.");
  599.         return;
  600.     }
  601.     (void) initgroups(pw->pw_name, pw->pw_gid);
  602.  
  603.     /* open wtmp before chroot */
  604.     (void)sprintf(ttyline, "ftp%d", getpid());
  605.     logwtmp(ttyline, pw->pw_name, remotehost);
  606.     logged_in = 1;
  607.  
  608.     if (guest) {
  609.         /*
  610.          * We MUST do a chdir() after the chroot. Otherwise
  611.          * the old current directory will be accessible as "."
  612.          * outside the new root!
  613.          */
  614.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  615.             reply(550, "Can't set guest privileges.");
  616.             goto bad;
  617.         }
  618.     } else if (chdir(pw->pw_dir) < 0) {
  619.         if (chdir("/") < 0) {
  620.             reply(530, "User %s: can't change directory to %s.",
  621.                 pw->pw_name, pw->pw_dir);
  622.             goto bad;
  623.         } else
  624.             lreply(230, "No directory! Logging in with home=/");
  625.     }
  626.     if (seteuid((uid_t)pw->pw_uid) < 0) {
  627.         reply(550, "Can't set uid.");
  628.         goto bad;
  629.     }
  630.     /*
  631.      * Display a login message, if it exists.
  632.      * N.B. reply(230,) must follow the message.
  633.      */
  634.     if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
  635.         char *cp, line[LINE_MAX];
  636.  
  637.         while (fgets(line, sizeof(line), fd) != NULL) {
  638.             if ((cp = strchr(line, '\n')) != NULL)
  639.                 *cp = '\0';
  640.             lreply(230, "%s", line);
  641.         }
  642.         (void) fflush(stdout);
  643.         (void) fclose(fd);
  644.     }
  645.     if (guest) {
  646.         reply(230, "Guest login ok, access restrictions apply.");
  647. #ifdef SETPROCTITLE
  648.         snprintf(proctitle, sizeof(proctitle),
  649.             "%s: anonymous/%.*s", remotehost,
  650.             sizeof(proctitle) - sizeof(remotehost) -
  651.             sizeof(": anonymous/"), passwd);
  652.         setproctitle(proctitle);
  653. #endif /* SETPROCTITLE */
  654.         if (logging)
  655.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
  656.                 remotehost, passwd);
  657.     } else {
  658.         reply(230, "User %s logged in.", pw->pw_name);
  659. #ifdef SETPROCTITLE
  660.         snprintf(proctitle, sizeof(proctitle),
  661.             "%s: %s", remotehost, pw->pw_name);
  662.         setproctitle(proctitle);
  663. #endif /* SETPROCTITLE */
  664.         if (logging)
  665.             syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
  666.                 remotehost, pw->pw_name);
  667.     }
  668.     (void) umask(defumask);
  669.     return;
  670. bad:
  671.     /* Forget all about it... */
  672.     end_login();
  673. }
  674.  
  675. void
  676. retrieve(cmd, name)
  677.     char *cmd, *name;
  678. {
  679.     FILE *fin, *dout;
  680.     struct stat st;
  681.     int (*closefunc) __P((FILE *));
  682.  
  683.     if (cmd == 0) {
  684.         fin = fopen(name, "r"), closefunc = fclose;
  685.         st.st_size = 0;
  686.     } else {
  687.         char line[BUFSIZ];
  688.  
  689.         (void) sprintf(line, cmd, name), name = line;
  690.         fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
  691.         st.st_size = -1;
  692.         st.st_blksize = BUFSIZ;
  693.     }
  694.     if (fin == NULL) {
  695.         if (errno != 0) {
  696.             perror_reply(550, name);
  697.             if (cmd == 0) {
  698.                 LOGCMD("get", name);
  699.             }
  700.         }
  701.         return;
  702.     }
  703.     byte_count = -1;
  704.     if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
  705.         reply(550, "%s: not a plain file.", name);
  706.         goto done;
  707.     }
  708.     if (restart_point) {
  709.         if (type == TYPE_A) {
  710.             off_t i, n;
  711.             int c;
  712.  
  713.             n = restart_point;
  714.             i = 0;
  715.             while (i++ < n) {
  716.                 if ((c=getc(fin)) == EOF) {
  717.                     perror_reply(550, name);
  718.                     goto done;
  719.                 }
  720.                 if (c == '\n')
  721.                     i++;
  722.             }
  723.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  724.             perror_reply(550, name);
  725.             goto done;
  726.         }
  727.     }
  728.     dout = dataconn(name, st.st_size, "w");
  729.     if (dout == NULL)
  730.         goto done;
  731.     send_data(fin, dout, st.st_blksize);
  732.     (void) fclose(dout);
  733.     data = -1;
  734.     pdata = -1;
  735. done:
  736.     if (cmd == 0)
  737.         LOGBYTES("get", name, byte_count);
  738.     (*closefunc)(fin);
  739. }
  740.  
  741. void
  742. store(name, mode, unique)
  743.     char *name, *mode;
  744.     int unique;
  745. {
  746.     FILE *fout, *din;
  747.     struct stat st;
  748.     int (*closefunc) __P((FILE *));
  749.  
  750.     if (unique && stat(name, &st) == 0 &&
  751.         (name = gunique(name)) == NULL) {
  752.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  753.         return;
  754.     }
  755.  
  756.     if (restart_point)
  757.         mode = "r+";
  758.     fout = fopen(name, mode);
  759.     closefunc = fclose;
  760.     if (fout == NULL) {
  761.         perror_reply(553, name);
  762.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  763.         return;
  764.     }
  765.     byte_count = -1;
  766.     if (restart_point) {
  767.         if (type == TYPE_A) {
  768.             off_t i, n;
  769.             int c;
  770.  
  771.             n = restart_point;
  772.             i = 0;
  773.             while (i++ < n) {
  774.                 if ((c=getc(fout)) == EOF) {
  775.                     perror_reply(550, name);
  776.                     goto done;
  777.                 }
  778.                 if (c == '\n')
  779.                     i++;
  780.             }
  781.             /*
  782.              * We must do this seek to "current" position
  783.              * because we are changing from reading to
  784.              * writing.
  785.              */
  786.             if (fseek(fout, 0L, L_INCR) < 0) {
  787.                 perror_reply(550, name);
  788.                 goto done;
  789.             }
  790.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  791.             perror_reply(550, name);
  792.             goto done;
  793.         }
  794.     }
  795.     din = dataconn(name, (off_t)-1, "r");
  796.     if (din == NULL)
  797.         goto done;
  798.     if (receive_data(din, fout) == 0) {
  799.         if (unique)
  800.             reply(226, "Transfer complete (unique file name:%s).",
  801.                 name);
  802.         else
  803.             reply(226, "Transfer complete.");
  804.     }
  805.     (void) fclose(din);
  806.     data = -1;
  807.     pdata = -1;
  808. done:
  809.     LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
  810.     (*closefunc)(fout);
  811. }
  812.  
  813. static FILE *
  814. getdatasock(mode)
  815.     char *mode;
  816. {
  817.     int on = 1, s, t, tries;
  818.  
  819.     if (data >= 0)
  820.         return (fdopen(data, mode));
  821.     (void) seteuid((uid_t)0);
  822.     s = socket(AF_INET, SOCK_STREAM, 0);
  823.     if (s < 0)
  824.         goto bad;
  825.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  826.         (char *) &on, sizeof(on)) < 0)
  827.         goto bad;
  828.     /* anchor socket to avoid multi-homing problems */
  829.     data_source.sin_family = AF_INET;
  830.     data_source.sin_addr = ctrl_addr.sin_addr;
  831.     for (tries = 1; ; tries++) {
  832.         if (bind(s, (struct sockaddr *)&data_source,
  833.             sizeof(data_source)) >= 0)
  834.             break;
  835.         if (errno != EADDRINUSE || tries > 10)
  836.             goto bad;
  837.         sleep(tries);
  838.     }
  839.     (void) seteuid((uid_t)pw->pw_uid);
  840. #if defined (IP_TOS) && defined (IPTOS_THROUGHPUT) && defined (IPPROTO_IP)
  841.     on = IPTOS_THROUGHPUT;
  842.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  843.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  844. #endif
  845.     return (fdopen(s, mode));
  846. bad:
  847.     /* Return the real value of errno (close may change it) */
  848.     t = errno;
  849.     (void) seteuid((uid_t)pw->pw_uid);
  850.     (void) close(s);
  851.     errno = t;
  852.     return (NULL);
  853. }
  854.  
  855. static FILE *
  856. dataconn(name, size, mode)
  857.     char *name;
  858.     off_t size;
  859.     char *mode;
  860. {
  861.     char sizebuf[32];
  862.     FILE *file;
  863.     int retry = 0, tos;
  864.  
  865.     file_size = size;
  866.     byte_count = 0;
  867.     if (size != (off_t) -1)
  868.         (void) sprintf(sizebuf, " (%s bytes)", off_to_str (size));
  869.     else
  870.         (void) strcpy(sizebuf, "");
  871.     if (pdata >= 0) {
  872.         struct sockaddr_in from;
  873.         int s, fromlen = sizeof(from);
  874.  
  875.         s = accept(pdata, (struct sockaddr *)&from, &fromlen);
  876.         if (s < 0) {
  877.             reply(425, "Can't open data connection.");
  878.             (void) close(pdata);
  879.             pdata = -1;
  880.             return (NULL);
  881.         }
  882.         (void) close(pdata);
  883.         pdata = s;
  884. #if defined (IP_TOS) && defined (IPTOS_LOWDELAY) && defined (IPPROTO_IP)
  885.         tos = IPTOS_LOWDELAY;
  886.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  887.             sizeof(int));
  888. #endif
  889.         reply(150, "Opening %s mode data connection for '%s'%s.",
  890.              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  891.         return (fdopen(pdata, mode));
  892.     }
  893.     if (data >= 0) {
  894.         reply(125, "Using existing data connection for '%s'%s.",
  895.             name, sizebuf);
  896.         usedefault = 1;
  897.         return (fdopen(data, mode));
  898.     }
  899.     if (usedefault)
  900.         data_dest = his_addr;
  901.     usedefault = 1;
  902.     file = getdatasock(mode);
  903.     if (file == NULL) {
  904.         reply(425, "Can't create data socket (%s,%d): %s.",
  905.             inet_ntoa(data_source.sin_addr),
  906.             ntohs(data_source.sin_port), strerror(errno));
  907.         return (NULL);
  908.     }
  909.     data = fileno(file);
  910.     while (connect(data, (struct sockaddr *)&data_dest,
  911.         sizeof(data_dest)) < 0) {
  912.         if (errno == EADDRINUSE && retry < swaitmax) {
  913.             sleep((unsigned) swaitint);
  914.             retry += swaitint;
  915.             continue;
  916.         }
  917.         perror_reply(425, "Can't build data connection");
  918.         (void) fclose(file);
  919.         data = -1;
  920.         return (NULL);
  921.     }
  922.     reply(150, "Opening %s mode data connection for '%s'%s.",
  923.          type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  924.     return (file);
  925. }
  926.  
  927. /*
  928.  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
  929.  * encapsulation of the data subject * to Mode, Structure, and Type.
  930.  *
  931.  * NB: Form isn't handled.
  932.  */
  933. static void
  934. send_data(instr, outstr, blksize)
  935.     FILE *instr, *outstr;
  936.     off_t blksize;
  937. {
  938.     int c, cnt, filefd, netfd;
  939.     char *buf;
  940.  
  941.     transflag++;
  942.     if (setjmp(urgcatch)) {
  943.         transflag = 0;
  944.         return;
  945.     }
  946.     switch (type) {
  947.  
  948.     case TYPE_A:
  949.         while ((c = getc(instr)) != EOF) {
  950.             byte_count++;
  951.             if (c == '\n') {
  952.                 if (ferror(outstr))
  953.                     goto data_err;
  954.                 (void) putc('\r', outstr);
  955.             }
  956.             (void) putc(c, outstr);
  957.         }
  958.         fflush(outstr);
  959.         transflag = 0;
  960.         if (ferror(instr))
  961.             goto file_err;
  962.         if (ferror(outstr))
  963.             goto data_err;
  964.         reply(226, "Transfer complete.");
  965.         return;
  966.  
  967.     case TYPE_I:
  968.     case TYPE_L:
  969.         if ((buf = malloc((u_int)blksize)) == NULL) {
  970.             transflag = 0;
  971.             perror_reply(451, "Local resource failure: malloc");
  972.             return;
  973.         }
  974.         netfd = fileno(outstr);
  975.         filefd = fileno(instr);
  976.         while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
  977.             write(netfd, buf, cnt) == cnt)
  978.             byte_count += cnt;
  979.         transflag = 0;
  980.         (void)free(buf);
  981.         if (cnt != 0) {
  982.             if (cnt < 0)
  983.                 goto file_err;
  984.             goto data_err;
  985.         }
  986.         reply(226, "Transfer complete.");
  987.         return;
  988.     default:
  989.         transflag = 0;
  990.         reply(550, "Unimplemented TYPE %d in send_data", type);
  991.         return;
  992.     }
  993.  
  994. data_err:
  995.     transflag = 0;
  996.     perror_reply(426, "Data connection");
  997.     return;
  998.  
  999. file_err:
  1000.     transflag = 0;
  1001.     perror_reply(551, "Error on input file");
  1002. }
  1003.  
  1004. /*
  1005.  * Transfer data from peer to "outstr" using the appropriate encapulation of
  1006.  * the data subject to Mode, Structure, and Type.
  1007.  *
  1008.  * N.B.: Form isn't handled.
  1009.  */
  1010. static int
  1011. receive_data(instr, outstr)
  1012.     FILE *instr, *outstr;
  1013. {
  1014.     int c;
  1015.     int cnt, bare_lfs = 0;
  1016.     char buf[BUFSIZ];
  1017.  
  1018.     transflag++;
  1019.     if (setjmp(urgcatch)) {
  1020.         transflag = 0;
  1021.         return (-1);
  1022.     }
  1023.     switch (type) {
  1024.  
  1025.     case TYPE_I:
  1026.     case TYPE_L:
  1027.         while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
  1028.             if (write(fileno(outstr), buf, cnt) != cnt)
  1029.                 goto file_err;
  1030.             byte_count += cnt;
  1031.         }
  1032.         if (cnt < 0)
  1033.             goto data_err;
  1034.         transflag = 0;
  1035.         return (0);
  1036.  
  1037.     case TYPE_E:
  1038.         reply(553, "TYPE E not implemented.");
  1039.         transflag = 0;
  1040.         return (-1);
  1041.  
  1042.     case TYPE_A:
  1043.         while ((c = getc(instr)) != EOF) {
  1044.             byte_count++;
  1045.             if (c == '\n')
  1046.                 bare_lfs++;
  1047.             while (c == '\r') {
  1048.                 if (ferror(outstr))
  1049.                     goto data_err;
  1050.                 if ((c = getc(instr)) != '\n') {
  1051.                     (void) putc ('\r', outstr);
  1052.                     if (c == '\0' || c == EOF)
  1053.                         goto contin2;
  1054.                 }
  1055.             }
  1056.             (void) putc(c, outstr);
  1057.     contin2:    ;
  1058.         }
  1059.         fflush(outstr);
  1060.         if (ferror(instr))
  1061.             goto data_err;
  1062.         if (ferror(outstr))
  1063.             goto file_err;
  1064.         transflag = 0;
  1065.         if (bare_lfs) {
  1066.             lreply(226,
  1067.         "WARNING! %d bare linefeeds received in ASCII mode",
  1068.                 bare_lfs);
  1069.         (void)printf("   File may not have transferred correctly.\r\n");
  1070.         }
  1071.         return (0);
  1072.     default:
  1073.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  1074.         transflag = 0;
  1075.         return (-1);
  1076.     }
  1077.  
  1078. data_err:
  1079.     transflag = 0;
  1080.     perror_reply(426, "Data Connection");
  1081.     return (-1);
  1082.  
  1083. file_err:
  1084.     transflag = 0;
  1085.     perror_reply(452, "Error writing file");
  1086.     return (-1);
  1087. }
  1088.  
  1089. void
  1090. statfilecmd(filename)
  1091.     char *filename;
  1092. {
  1093.     FILE *fin;
  1094.     int c;
  1095.     char line[LINE_MAX];
  1096.  
  1097.     (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
  1098.     fin = ftpd_popen(line, "r");
  1099.     lreply(211, "status of %s:", filename);
  1100.     while ((c = getc(fin)) != EOF) {
  1101.         if (c == '\n') {
  1102.             if (ferror(stdout)){
  1103.                 perror_reply(421, "control connection");
  1104.                 (void) ftpd_pclose(fin);
  1105.                 dologout(1);
  1106.                 /* NOTREACHED */
  1107.             }
  1108.             if (ferror(fin)) {
  1109.                 perror_reply(551, filename);
  1110.                 (void) ftpd_pclose(fin);
  1111.                 return;
  1112.             }
  1113.             (void) putc('\r', stdout);
  1114.         }
  1115.         (void) putc(c, stdout);
  1116.     }
  1117.     (void) ftpd_pclose(fin);
  1118.     reply(211, "End of Status");
  1119. }
  1120.  
  1121. void
  1122. statcmd()
  1123. {
  1124.     struct sockaddr_in *sin;
  1125.     u_char *a, *p;
  1126.  
  1127.     lreply(211, "%s FTP server status:", hostname, version);
  1128.     printf("     %s\r\n", version);
  1129.     printf("     Connected to %s", remotehost);
  1130.     if (!isdigit(remotehost[0]))
  1131.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  1132.     printf("\r\n");
  1133.     if (logged_in) {
  1134.         if (guest)
  1135.             printf("     Logged in anonymously\r\n");
  1136.         else
  1137.             printf("     Logged in as %s\r\n", pw->pw_name);
  1138.     } else if (askpasswd)
  1139.         printf("     Waiting for password\r\n");
  1140.     else
  1141.         printf("     Waiting for user name\r\n");
  1142.     printf("     TYPE: %s", typenames[type]);
  1143.     if (type == TYPE_A || type == TYPE_E)
  1144.         printf(", FORM: %s", formnames[form]);
  1145.     if (type == TYPE_L)
  1146. #ifdef CHAR_BIT
  1147.         printf(" %d", CHAR_BIT);
  1148. #else
  1149. #if NBBY == 8
  1150.         printf(" %d", NBBY);
  1151. #else
  1152.         printf(" %d", bytesize);    /* need definition! */
  1153. #endif
  1154. #endif
  1155.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  1156.         strunames[stru], modenames[mode]);
  1157.     if (data != -1)
  1158.         printf("     Data connection open\r\n");
  1159.     else if (pdata != -1) {
  1160.         printf("     in Passive mode");
  1161.         sin = &pasv_addr;
  1162.         goto printaddr;
  1163.     } else if (usedefault == 0) {
  1164.         printf("     PORT");
  1165.         sin = &data_dest;
  1166. printaddr:
  1167.         a = (u_char *) &sin->sin_addr;
  1168.         p = (u_char *) &sin->sin_port;
  1169. #define UC(b) (((int) b) & 0xff)
  1170.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  1171.             UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1172. #undef UC
  1173.     } else
  1174.         printf("     No data connection\r\n");
  1175.     reply(211, "End of status");
  1176. }
  1177.  
  1178. void
  1179. fatal(s)
  1180.     char *s;
  1181. {
  1182.  
  1183.     reply(451, "Error in server: %s\n", s);
  1184.     reply(221, "Closing connection due to server error.");
  1185.     dologout(0);
  1186.     /* NOTREACHED */
  1187. }
  1188.  
  1189. void
  1190. #if __STDC__
  1191. reply(int n, const char *fmt, ...)
  1192. #else
  1193. reply(n, fmt, va_alist)
  1194.     int n;
  1195.     char *fmt;
  1196.         va_dcl
  1197. #endif
  1198. {
  1199.     va_list ap;
  1200. #if __STDC__
  1201.     va_start(ap, fmt);
  1202. #else
  1203.     va_start(ap);
  1204. #endif
  1205.     (void)printf("%d ", n);
  1206.     (void)vprintf(fmt, ap);
  1207.     (void)printf("\r\n");
  1208.     (void)fflush(stdout);
  1209.     if (debug) {
  1210.         syslog(LOG_DEBUG, "<--- %d ", n);
  1211.         vsyslog(LOG_DEBUG, fmt, ap);
  1212.     }
  1213. }
  1214.  
  1215. void
  1216. #if __STDC__
  1217. lreply(int n, const char *fmt, ...)
  1218. #else
  1219. lreply(n, fmt, va_alist)
  1220.     int n;
  1221.     char *fmt;
  1222.         va_dcl
  1223. #endif
  1224. {
  1225.     va_list ap;
  1226. #if __STDC__
  1227.     va_start(ap, fmt);
  1228. #else
  1229.     va_start(ap);
  1230. #endif
  1231.     (void)printf("%d- ", n);
  1232.     (void)vprintf(fmt, ap);
  1233.     (void)printf("\r\n");
  1234.     (void)fflush(stdout);
  1235.     if (debug) {
  1236.         syslog(LOG_DEBUG, "<--- %d- ", n);
  1237.         vsyslog(LOG_DEBUG, fmt, ap);
  1238.     }
  1239. }
  1240.  
  1241. static void
  1242. ack(s)
  1243.     char *s;
  1244. {
  1245.  
  1246.     reply(250, "%s command successful.", s);
  1247. }
  1248.  
  1249. void
  1250. nack(s)
  1251.     char *s;
  1252. {
  1253.  
  1254.     reply(502, "%s command not implemented.", s);
  1255. }
  1256.  
  1257. /* ARGSUSED */
  1258. void
  1259. yyerror(s)
  1260.     char *s;
  1261. {
  1262.     char *cp;
  1263.  
  1264.     if (cp = strchr(cbuf,'\n'))
  1265.         *cp = '\0';
  1266.     reply(500, "'%s': command not understood.", cbuf);
  1267. }
  1268.  
  1269. void
  1270. delete(name)
  1271.     char *name;
  1272. {
  1273.     struct stat st;
  1274.  
  1275.     LOGCMD("delete", name);
  1276.     if (stat(name, &st) < 0) {
  1277.         perror_reply(550, name);
  1278.         return;
  1279.     }
  1280.     if ((st.st_mode&S_IFMT) == S_IFDIR) {
  1281.         if (rmdir(name) < 0) {
  1282.             perror_reply(550, name);
  1283.             return;
  1284.         }
  1285.         goto done;
  1286.     }
  1287.     if (unlink(name) < 0) {
  1288.         perror_reply(550, name);
  1289.         return;
  1290.     }
  1291. done:
  1292.     ack("DELE");
  1293. }
  1294.  
  1295. void
  1296. cwd(path)
  1297.     char *path;
  1298. {
  1299.  
  1300.     if (chdir(path) < 0)
  1301.         perror_reply(550, path);
  1302.     else
  1303.         ack("CWD");
  1304. }
  1305.  
  1306. void
  1307. makedir(name)
  1308.     char *name;
  1309. {
  1310.  
  1311.     LOGCMD("mkdir", name);
  1312.     if (mkdir(name, 0777) < 0)
  1313.         perror_reply(550, name);
  1314.     else
  1315.         reply(257, "MKD command successful.");
  1316. }
  1317.  
  1318. void
  1319. removedir(name)
  1320.     char *name;
  1321. {
  1322.  
  1323.     LOGCMD("rmdir", name);
  1324.     if (rmdir(name) < 0)
  1325.         perror_reply(550, name);
  1326.     else
  1327.         ack("RMD");
  1328. }
  1329.  
  1330. void
  1331. pwd()
  1332. {
  1333.     char *path = getcwd (0, 0);
  1334.     if (path) {
  1335.         reply(257, "\"%s\" is current directory.", path);
  1336.         free (path);
  1337.     } else
  1338.         reply(550, "%s.", strerror (errno));
  1339. }
  1340.  
  1341. char *
  1342. renamefrom(name)
  1343.     char *name;
  1344. {
  1345.     struct stat st;
  1346.  
  1347.     if (stat(name, &st) < 0) {
  1348.         perror_reply(550, name);
  1349.         return ((char *)0);
  1350.     }
  1351.     reply(350, "File exists, ready for destination name");
  1352.     return (name);
  1353. }
  1354.  
  1355. void
  1356. renamecmd(from, to)
  1357.     char *from, *to;
  1358. {
  1359.  
  1360.     LOGCMD2("rename", from, to);
  1361.     if (rename(from, to) < 0)
  1362.         perror_reply(550, "rename");
  1363.     else
  1364.         ack("RNTO");
  1365. }
  1366.  
  1367. static void
  1368. dolog(sin)
  1369.     struct sockaddr_in *sin;
  1370. {
  1371.     char *name;
  1372.     struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
  1373.         sizeof(struct in_addr), AF_INET);
  1374.  
  1375.     if (hp)
  1376.         name = hp->h_name;
  1377.     else
  1378.         name = inet_ntoa(sin->sin_addr);
  1379.  
  1380.     if (remotehost)
  1381.         free (remotehost);
  1382.     remotehost = malloc (strlen (name));
  1383.     strcpy (remotehost, name);
  1384.  
  1385. #ifdef SETPROCTITLE
  1386.     snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
  1387.     setproctitle(proctitle);
  1388. #endif /* SETPROCTITLE */
  1389.  
  1390.     if (logging)
  1391.         syslog(LOG_INFO, "connection from %s", remotehost);
  1392. }
  1393.  
  1394. /*
  1395.  * Record logout in wtmp file
  1396.  * and exit with supplied status.
  1397.  */
  1398. void
  1399. dologout(status)
  1400.     int status;
  1401. {
  1402.  
  1403.     if (logged_in) {
  1404.         (void) seteuid((uid_t)0);
  1405.         logwtmp(ttyline, "", "");
  1406.     }
  1407.     /* beware of flushing buffers after a SIGPIPE */
  1408.     _exit(status);
  1409. }
  1410.  
  1411. static void
  1412. myoob(signo)
  1413.     int signo;
  1414. {
  1415.     char *cp;
  1416.  
  1417.     /* only process if transfer occurring */
  1418.     if (!transflag)
  1419.         return;
  1420.     cp = tmpline;
  1421.     if (telnet_fgets(cp, 7, stdin) == NULL) {
  1422.         reply(221, "You could at least say goodbye.");
  1423.         dologout(0);
  1424.     }
  1425.     upper(cp);
  1426.     if (strcmp(cp, "ABOR\r\n") == 0) {
  1427.         tmpline[0] = '\0';
  1428.         reply(426, "Transfer aborted. Data connection closed.");
  1429.         reply(226, "Abort successful");
  1430.         longjmp(urgcatch, 1);
  1431.     }
  1432.     if (strcmp(cp, "STAT\r\n") == 0) {
  1433.         if (file_size != (off_t) -1)
  1434.             reply(213, "Status: %s of %s bytes transferred",
  1435.                 off_to_str (byte_count), off_to_str (file_size));
  1436.         else
  1437.             reply(213, "Status: %s bytes transferred",
  1438.                   off_to_str (byte_count));
  1439.     }
  1440. }
  1441.  
  1442. /*
  1443.  * Note: a response of 425 is not mentioned as a possible response to
  1444.  *    the PASV command in RFC959. However, it has been blessed as
  1445.  *    a legitimate response by Jon Postel in a telephone conversation
  1446.  *    with Rick Adams on 25 Jan 89.
  1447.  */
  1448. void
  1449. passive()
  1450. {
  1451.     int len;
  1452.     char *p, *a;
  1453.  
  1454.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  1455.     if (pdata < 0) {
  1456.         perror_reply(425, "Can't open passive connection");
  1457.         return;
  1458.     }
  1459.     pasv_addr = ctrl_addr;
  1460.     pasv_addr.sin_port = 0;
  1461.     (void) seteuid((uid_t)0);
  1462.     if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
  1463.         (void) seteuid((uid_t)pw->pw_uid);
  1464.         goto pasv_error;
  1465.     }
  1466.     (void) seteuid((uid_t)pw->pw_uid);
  1467.     len = sizeof(pasv_addr);
  1468.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  1469.         goto pasv_error;
  1470.     if (listen(pdata, 1) < 0)
  1471.         goto pasv_error;
  1472.     a = (char *) &pasv_addr.sin_addr;
  1473.     p = (char *) &pasv_addr.sin_port;
  1474.  
  1475. #define UC(b) (((int) b) & 0xff)
  1476.  
  1477.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  1478.         UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1479.     return;
  1480.  
  1481. pasv_error:
  1482.     (void) close(pdata);
  1483.     pdata = -1;
  1484.     perror_reply(425, "Can't open passive connection");
  1485.     return;
  1486. }
  1487.  
  1488. /*
  1489.  * Generate unique name for file with basename "local".
  1490.  * The file named "local" is already known to exist.
  1491.  * Generates failure reply on error.
  1492.  */
  1493. static char *
  1494. gunique(local)
  1495.     char *local;
  1496. {
  1497.     static char *new = 0;
  1498.     struct stat st;
  1499.     int count;
  1500.     char *cp;
  1501.  
  1502.     cp = strrchr(local, '/');
  1503.     if (cp)
  1504.         *cp = '\0';
  1505.     if (stat(cp ? local : ".", &st) < 0) {
  1506.         perror_reply(553, cp ? local : ".");
  1507.         return ((char *) 0);
  1508.     }
  1509.     if (cp)
  1510.         *cp = '/';
  1511.  
  1512.     if (new)
  1513.         free (new);
  1514.  
  1515.     new = malloc (strlen (local) + 5); /* '.' + DIG + DIG + '\0' */
  1516.     if (new) {
  1517.         strcpy(new, local);
  1518.         cp = new + strlen(new);
  1519.         *cp++ = '.';
  1520.         for (count = 1; count < 100; count++) {
  1521.             (void)sprintf(cp, "%d", count);
  1522.             if (stat(new, &st) < 0)
  1523.                 return (new);
  1524.         }
  1525.     }
  1526.  
  1527.     reply(452, "Unique file name cannot be created.");
  1528.     return (NULL);
  1529. }
  1530.  
  1531. /*
  1532.  * Format and send reply containing system error number.
  1533.  */
  1534. void
  1535. perror_reply(code, string)
  1536.     int code;
  1537.     char *string;
  1538. {
  1539.  
  1540.     reply(code, "%s: %s.", string, strerror(errno));
  1541. }
  1542.  
  1543. static char *onefile[] = {
  1544.     "",
  1545.     0
  1546. };
  1547.  
  1548. void
  1549. send_file_list(whichf)
  1550.     char *whichf;
  1551. {
  1552.     struct stat st;
  1553.     DIR *dirp = NULL;
  1554.     struct dirent *dir;
  1555.     FILE *dout = NULL;
  1556.     char **dirlist, *dirname;
  1557.     int simple = 0;
  1558.     int freeglob = 0;
  1559.     glob_t gl;
  1560.  
  1561.     if (strpbrk(whichf, "~{[*?") != NULL) {
  1562.         int flags = GLOB_NOCHECK;
  1563.  
  1564. #ifdef GLOB_BRACE
  1565.         flags |= GLOB_BRACE;
  1566. #endif
  1567. #ifdef GLOB_QUOTE
  1568.         flags |= GLOB_QUOTE;
  1569. #endif
  1570. #ifdef GLOB_TILDE
  1571.         flags |= GLOB_TILDE;
  1572. #endif
  1573.  
  1574.         memset(&gl, 0, sizeof(gl));
  1575.         freeglob = 1;
  1576.         if (glob(whichf, flags, 0, &gl)) {
  1577.             reply(550, "not found");
  1578.             goto out;
  1579.         } else if (gl.gl_pathc == 0) {
  1580.             errno = ENOENT;
  1581.             perror_reply(550, whichf);
  1582.             goto out;
  1583.         }
  1584.         dirlist = gl.gl_pathv;
  1585.     } else {
  1586.         onefile[0] = whichf;
  1587.         dirlist = onefile;
  1588.         simple = 1;
  1589.     }
  1590.  
  1591.     if (setjmp(urgcatch)) {
  1592.         transflag = 0;
  1593.         goto out;
  1594.     }
  1595.     while (dirname = *dirlist++) {
  1596.         if (stat(dirname, &st) < 0) {
  1597.             /*
  1598.              * If user typed "ls -l", etc, and the client
  1599.              * used NLST, do what the user meant.
  1600.              */
  1601.             if (dirname[0] == '-' && *dirlist == NULL &&
  1602.                 transflag == 0) {
  1603.                 retrieve("/bin/ls %s", dirname);
  1604.                 goto out;
  1605.             }
  1606.             perror_reply(550, whichf);
  1607.             if (dout != NULL) {
  1608.                 (void) fclose(dout);
  1609.                 transflag = 0;
  1610.                 data = -1;
  1611.                 pdata = -1;
  1612.             }
  1613.             goto out;
  1614.         }
  1615.  
  1616.         if (S_ISREG(st.st_mode)) {
  1617.             if (dout == NULL) {
  1618.                 dout = dataconn("file list", (off_t)-1, "w");
  1619.                 if (dout == NULL)
  1620.                     goto out;
  1621.                 transflag++;
  1622.             }
  1623.             fprintf(dout, "%s%s\n", dirname,
  1624.                 type == TYPE_A ? "\r" : "");
  1625.             byte_count += strlen(dirname) + 1;
  1626.             continue;
  1627.         } else if (!S_ISDIR(st.st_mode))
  1628.             continue;
  1629.  
  1630.         if ((dirp = opendir(dirname)) == NULL)
  1631.             continue;
  1632.  
  1633.         while ((dir = readdir(dirp)) != NULL) {
  1634.             char *nbuf;
  1635.  
  1636.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  1637.                 continue;
  1638.             if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
  1639.                 dir->d_namlen == 2)
  1640.                 continue;
  1641.  
  1642.             nbuf = alloca (strlen (dirname) + 1 + strlen (dir->d_name) + 1);
  1643.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  1644.  
  1645.             /*
  1646.              * We have to do a stat to insure it's
  1647.              * not a directory or special file.
  1648.              */
  1649.             if (simple || (stat(nbuf, &st) == 0 &&
  1650.                 S_ISREG(st.st_mode))) {
  1651.                 if (dout == NULL) {
  1652.                     dout = dataconn("file list", (off_t)-1,
  1653.                         "w");
  1654.                     if (dout == NULL)
  1655.                         goto out;
  1656.                     transflag++;
  1657.                 }
  1658.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  1659.                     fprintf(dout, "%s%s\n", &nbuf[2],
  1660.                         type == TYPE_A ? "\r" : "");
  1661.                 else
  1662.                     fprintf(dout, "%s%s\n", nbuf,
  1663.                         type == TYPE_A ? "\r" : "");
  1664.                 byte_count += strlen(nbuf) + 1;
  1665.             }
  1666.         }
  1667.         (void) closedir(dirp);
  1668.     }
  1669.  
  1670.     if (dout == NULL)
  1671.         reply(550, "No files found.");
  1672.     else if (ferror(dout) != 0)
  1673.         perror_reply(550, "Data connection");
  1674.     else
  1675.         reply(226, "Transfer complete.");
  1676.  
  1677.     transflag = 0;
  1678.     if (dout != NULL)
  1679.         (void) fclose(dout);
  1680.     data = -1;
  1681.     pdata = -1;
  1682. out:
  1683.     if (freeglob) {
  1684.         freeglob = 0;
  1685.         globfree(&gl);
  1686.     }
  1687. }
  1688.  
  1689. #ifdef SETPROCTITLE
  1690. /*
  1691.  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
  1692.  * Warning, since this is usually started from inetd.conf, it often doesn't
  1693.  * have much of an environment or arglist to overwrite.
  1694.  */
  1695. void
  1696. #if __STDC__
  1697. setproctitle(const char *fmt, ...)
  1698. #else
  1699. setproctitle(fmt, va_alist)
  1700.     char *fmt;
  1701.         va_dcl
  1702. #endif
  1703. {
  1704.     int i;
  1705.     va_list ap;
  1706.     char *p, *bp, ch;
  1707.     char buf[LINE_MAX];
  1708.  
  1709. #if __STDC__
  1710.     va_start(ap, fmt);
  1711. #else
  1712.     va_start(ap);
  1713. #endif
  1714.     (void)vsnprintf(buf, sizeof(buf), fmt, ap);
  1715.  
  1716.     /* make ps print our process name */
  1717.     p = Argv[0];
  1718.     *p++ = '-';
  1719.  
  1720.     i = strlen(buf);
  1721.     if (i > LastArgv - p - 2) {
  1722.         i = LastArgv - p - 2;
  1723.         buf[i] = '\0';
  1724.     }
  1725.     bp = buf;
  1726.     while (ch = *bp++)
  1727.         if (ch != '\n' && ch != '\r')
  1728.             *p++ = ch;
  1729.     while (p < LastArgv)
  1730.         *p++ = ' ';
  1731. }
  1732. #endif /* SETPROCTITLE */
  1733.